/*
 * The MIT License
 *
 * Copyright 2014 David Rodenas Pico.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package edu.uoc.sd.fr14.actors;

import edu.uoc.sd.fr14.model.CustomerId;
import edu.uoc.sd.fr14.model.FlightId;
import edu.uoc.sd.fr14.model.Nseq;
import edu.uoc.sd.fr14.model.OpId;
import edu.uoc.sd.fr14.model.ProxyId;
import edu.uoc.sd.fr14.model.ServerId;
import edu.uoc.sd.fr14.model.SubLog;

/**
 *
 * @author drodenas
 */
public interface Server extends Proxy {

	/**
     * This is the answer for a query message.
     * <p>
     * 
     * It reports to the customer as an answer that
     * the flight has freeSeats.
     * <p>
     * 
     * This method is invoked by the system automatically when
     * the customer receives a QueriedMessage.
     * 
     * 
     * @param flight    the flight that was requested 
     * @param freeSeats the number of free seats
     */

	/**
	 * This method is invoked when the server receives an abort.
	 * <p>
	 * 
	 * In this method you will deal with an abort request,
	 * this usually happens when you as a leader has sent a 
	 * prepare operation to a other leader and this leader request
	 * to abort the write operation, or when you tried to become
	 * leader in an election and another server with higher
	 * id wants you to cancel elections.
	 * In any case you should step down.
	 * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives an abort message. 
	 */
    void abort();
    
    /**
     * Request to apply a sublog of operations into the server state.
     * <p>
     * 
     * In this operation for the given from server and the nseq
     * sequence number operation you should check that nseq matches
     * with the expected that you want to receive, and if it is
     * true you apply ops to the operation.
     * If nseq is not expected then you should request with
     * a recover message the exact last nseq that you have seen.
     * If nseq matched, once operations are applied, you should
     * increment the next expected nseq to the last seen plus
     * the number of operations applied.
     * 
     * <p>
     * Sublog received as ops should be applied to the state
     * but it should not be recorded in its own server log.
     * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives an apply message.
	 *  
     * @param nseq it is the number of the first operation received from the server from at ops
     * @param ops  the piece of log from the server from starting at position nseq 
     * @param from the server who sends their own log operations to be applied in this other server
     */
    void apply(Nseq nseq, SubLog ops, ServerId from);
    
    /**
     * Request from a customer to confirm the customer in the flight.
     * <p>
     * 
     * In this operation you should confirm locally in your 
     * available state if the customer is seat in the provided
     * flight.
     * 
     * <p>
     * As an answer you should generate a confirmed message
     * to the customer with the result of the operation.
	 *  
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a confirm message.
     * 
     * @param flight   flight in which the customer wants to know if it has seat
     * @param customer customer that wants to know if has seat
     */
    void confirm(FlightId flight, CustomerId customer);
    
    /**
     * Request from a lower server id to become leader.
     * <p>
     * 
     * In this operation you receive a petition from the lower id server to become leader.
     * Because we are using bully algorithm you should abort that to become true.
     * The way to abort it is to *respond* with an abort message to that server.
     * If this abort message is lost, or if you do not receive an elect message,
     * a lower id server can become leader. 
     * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives an elect message.
     * 
     * @param from a lower id server who wants to become leader
     */
    void elect(ServerId from);
    
    /**
     * Request from a leader to be ready to accept a operation.
     * <p>
     * 
     * In this operation a leader request permisson to apply a write operation.
     * If you are a follower you should respond with a prepared message using
     * the same op id. 
     * If you are a leader you should abort this write operation and
     * send an abort message to the server. Optionally you may step down.
     * If the leader was unknown it should record the from server as a leader.
     * 
     * <p>
     * Note that op only is used to make a prepared message.
     * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a confirm message.
     * 
     * @param op   the op id that wants to apply
     * @param from the server id (which should be leader) that request to prepare
     */
    void prepare(OpId op, ServerId from);
    
    /**
     * Response from a follower that he is ready to accept a write operation.
	 * <p>
	 * 
	 * In this operation a server let you know that he is a follower ready 
	 * to accept a write operation (later sent as apply).
	 * This operation is invoked generally after you as a server have
	 * received a seat operation, then you have sent prepare operations
	 * to followers, and then you start to receive multiple prepaper
	 * for the same op id.
	 * When you have received enough prepared confirmations for the same
	 * op id given the current cluster quorum then you can perform the seat
	 * operation:
	 *   apply the seat operation to the current state
	 *   save the seat operation to the log
	 *   send an apply message to all followers to update their states
	 *      (using the last nseq just to be quick, 
	 *      if any is out of sync
	 *      will answer with a recover message)
	 *   reply to the customer with the confirmed message
	 *   cancel any timeout related to the prepare operation
	 * <p>
	 * 
	 * Note that this operation really implements the seat operation,
	 * because only here we are quite sure that there are not other
	 * leaders and we can apply it.
	 * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a prepared message.
     * 
     * @param op the op id of a previous prepare message corresponding with a seat operation
     */
    void prepared(OpId op);
    
    /**
     * Request from a customer to know how many free seats are available flight.
     * <p>
     * 
     * In this operation you should count locally in your 
     * available state how many available seats are.
     * 
     * <p>
     * As an answer you should generate a queried message
     * to the customer with the result of the operation.
	 *  
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a query message.
     * 
     * @param flight flight in which we want to know how many seats are available
     * @param from   the customer who wants to know and is who wants to receive the answer
     */
    void query(FlightId flight, CustomerId from);
    
    /**
     * Request from a customer to be seat in a flight,
     * or proxied from a follower.
     * <p>
     * 
     * If you are not leader and you do not know who is the leader
     * you should start a new election to try to become leader.
     * In that case you do not need to answer to the customer,
     * the customer will retry later.
     * To start elections you should program the clock because you
     * need to be called twice: one to begin elections (which
     * could happen inmediately), and another second time
     * to become leader if other servers have nothing against you
     * (do not prevent/abort you to become leader).
     * 
     * <p>
     * If you are a follower you should proxy (send to) 
     * this request to the leader. 
     * In that case you should send a message to the leader with
     * fligh and customer, and you as a from, and set
     * a timeout to know if the leader responds in time.
     * 
     * <p>
     * If you are leader, you should start a seat/write operation.
     * Seat operation properly 
     * (modify the state and save the operation to the log) 
     * should be performed after enough prepared messages
     * are received by the leader.
     * In this operation,
     *   you have to prepare a seat operation, 
     *   you have to create an operation id and annotate it for later retrieval,
     *   you have to send to other servers a prepare message to confirm writing,
     *   you have to set the prepare timeout just to know if there is any problem in the network.
     * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a prepare message.
     * 
     * @param flight
     * @param customer
     * @param from
     */
    void seat(FlightId flight, CustomerId customer, ProxyId from);
    
    /**
     * A request from other server to recover a part of the log of this server. 
	 * <p>
	 * 
	 * When a server receives this message is because another server is
	 * requesting to synchronize its own state with potentially lost operations
	 * recorded in the current server log.
	 * In this operation an nseq is specified for the last log operation known
	 * by the from server and an answer has to be generated.
	 * You should send an apply message to the from server with 
	 * a sublog of this server log starting at nseq to the end 
	 * (which could be eventually empty, nothing new, or everything, starting at 0).
	 * <p>
	 * 
	 * Additionally this method also reports if the current server
	 * is leader. If it is true, and this server is leader
	 * this server should step down (optionally can send an abort
	 * operation to the from server).
	 * If leader is true, you should record from server as a new leader.
	 * 
	 * 
	 * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a recover message.
     * 
     * @param nseq   first log position that from server wants to receive (last seen from from)
     * @param leader if the from server is a leader
     * @param from   the server who sent this message
     */
    void recover(Nseq nseq, boolean leader, ServerId from);
    
    /**
     * A timeout event triggered by the clock to start elections.
     * <p>
     * 
     * With this method the server will perform all required steps
     * to become a leader. After this timeout an timeoutElectionEnd
     * is always triggered, that, if it works well, this server will become leader.
     * <p>
     * 
     * In this operation the server will send to all greater id servers
     * an elect message proposing itself as a leader. It also
     * has to annotate that he has started an election.
     * If any abort operation is received, it cancels (clears) that this server
     * is in elections.
     * 
     * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a timeoutElectionBegin message.
     */
    void timeoutElectionBegin();
    
    /**
     * A timeout event triggered by the clock when an election period is finished.
     * <p>
     * 
     * This method is used to compute if the current server will become a leader.
     * If the server in elections (has started an election and it is not cancelled)
     * it becomes a leader.
     * 
     * When becomes a leader it has to send a recover message to all other 
     * servers for two reason: to have the most up-to-date possible state,
     * and to report to other servers that he is the (only truthfully) leader. 
	 *
     * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a timeoutElectionEnd message.
     */
    void timeoutElectionEnd();
    
    /**
     * An interval timeout event triggered by the clock to synchronize current state.
     * <p>
     * 
     * Every a fixed interval of time each server has to synchronize its
     * state towards all other servers.
     * When this method is invoked you should send a recover message
     * to all other servers providing the last log operation number received
     * for each server. 
	 *
     * <p>
	 * This method is invoked by the system automatically
	 * when the server receives a synchronize message.
     */
    void synchronize();
    
}
